#include "ShapeContextPresenter.h"
#include "ShapeContextPresenter.moc"

#include <iostream>

ShapeContextPresenter::ShapeContextPresenter(ShapeContextGenerator* descriptor, ParameterWidget* peakParameter):
    DescriptorPresenter(descriptor, peakParameter)
{
    m_descriptorParameter->addDoubleParameter("minRho", "Minimum radial distance", 0.05, 0.);
    m_descriptorParameter->addDoubleParameter("maxRho", "Maximum radial distance", 0.4, 0.);
    m_descriptorParameter->addIntParameter("binRho", "Number of radial bins", 4, 1);
    m_descriptorParameter->addIntParameter("binPhi", "Number of angular bins", 12, 1);
    m_descriptorParameter->addEnumParameter("distanceFunction", "Histogram distance function");
    syncronize();
    reconnect();
}

void ShapeContextPresenter::setDescriptor(DescriptorGenerator* descriptor){
    m_descriptor = descriptor;
    syncronize();
}

void ShapeContextPresenter::setDescriptorParameter(ParameterWidget* peakParameter){
    disconnect(m_descriptorParameter, 0, this, 0);
    m_descriptorParameter = peakParameter;
    m_descriptorParameter->clearParameterMap();
    m_descriptorParameter->addDoubleParameter("minRho", "Minimum radial distance", 0.05, 0.);
    m_descriptorParameter->addDoubleParameter("maxRho", "Maximum radial distance", 0.4, 0.);
    m_descriptorParameter->addIntParameter("binRho", "Number of radial bins", 4, 1);
    m_descriptorParameter->addIntParameter("binPhi", "Number of angular bins", 12, 1);
    m_descriptorParameter->addEnumParameter("distanceFunction", "Histogram distance function");
    syncronize();
    reconnect();
}

void ShapeContextPresenter::insertDistanceFunction(const QString& name, const HistogramDistance<double>* distanceFunction){
    m_distanceFunctionNames.append(name);
    m_distanceFunctions.push_back(distanceFunction);
    m_descriptorParameter->insertEnumValue("distanceFunction", name);
    if(m_distanceFunctions.size() == 1){ 
	m_currentDistanceFunction = distanceFunction;
	m_currentDistanceFunctionIndex = 0;
	ShapeContextGenerator *descriptor = (ShapeContextGenerator *) m_descriptor;
	descriptor->setDistanceFunction(m_currentDistanceFunction);
    }
}

void ShapeContextPresenter::changeParameter(const QString& name){
    if(!QString::compare(name, "minRho")){
	double guiValue;
	bool valid = m_descriptorParameter->getDoubleValue("minRho", guiValue);
	if(valid) {changeMinRho(guiValue);}
    } else if(!QString::compare(name, "maxRho")){
	double guiValue;
	bool valid = m_descriptorParameter->getDoubleValue("maxRho", guiValue);
	if(valid) {changeMaxRho(guiValue);}
    }else if(!QString::compare(name, "binRho")){
	int guiValue;
	bool valid = m_descriptorParameter->getIntValue("binRho", guiValue);
	if(valid) {changeBinRho(guiValue);}
    }else if(!QString::compare(name, "binPhi")){
	int guiValue;
	bool valid = m_descriptorParameter->getIntValue("binPhi", guiValue);
	if(valid) {changeBinPhi(guiValue);}
    }else if(!QString::compare(name, "distanceFunction")){
	int guiValue;
	bool valid = m_descriptorParameter->getEnumValue("distanceFunction", guiValue);
	if(valid) {changeDistanceFunction(guiValue);}
    }
}


void ShapeContextPresenter::changeMinRho(double value){
    ShapeContextGenerator *descriptor = (ShapeContextGenerator *) m_descriptor;
    double guiValue; 
    m_descriptorParameter->getDoubleValue(QString("minRho"), guiValue);
    if(descriptor->getMinRho() != value ||  guiValue != value){
	descriptor->setEdges(value, descriptor->getMaxRho(), descriptor->getBinRho(), descriptor->getBinPhi());
	m_descriptorParameter->setDoubleValue("minRho", descriptor->getMinRho());
	emit descriptorChanged();
    }
}

void ShapeContextPresenter::changeMaxRho(double value){
    ShapeContextGenerator *descriptor = (ShapeContextGenerator *) m_descriptor;
    double guiValue; 
    m_descriptorParameter->getDoubleValue("maxRho", guiValue);
    if(descriptor->getMaxRho() != value || guiValue != value){
	descriptor->setEdges(descriptor->getMinRho(), value, descriptor->getBinRho(), descriptor->getBinPhi());
	m_descriptorParameter->setDoubleValue("maxRho", descriptor->getMaxRho());
	emit descriptorChanged();
    }
}

void ShapeContextPresenter::changeBinRho(int value){
    ShapeContextGenerator *descriptor = (ShapeContextGenerator *) m_descriptor;
    int guiValue; 
    m_descriptorParameter->getIntValue(QString("binRho"), guiValue);
    if(descriptor->getBinRho() != (unsigned int)value ||  guiValue != value){
	descriptor->setEdges(descriptor->getMinRho(), descriptor->getMaxRho(), value, descriptor->getBinPhi());
	m_descriptorParameter->setIntValue("binRho", descriptor->getBinRho());
	emit descriptorChanged();
    }
}

void ShapeContextPresenter::changeBinPhi(int value){
    ShapeContextGenerator *descriptor = (ShapeContextGenerator *) m_descriptor;
    int guiValue; 
    m_descriptorParameter->getIntValue(QString("binPhi"), guiValue);
    if(descriptor->getBinPhi() != (unsigned int)value ||  guiValue != value){
	descriptor->setEdges(descriptor->getMinRho(), descriptor->getMaxRho(), descriptor->getBinRho(), value);
	m_descriptorParameter->setIntValue("binPhi", descriptor->getBinPhi());
	emit descriptorChanged();
    }
}

void ShapeContextPresenter::changeDistanceFunction(int value){
    ShapeContextGenerator *descriptor = (ShapeContextGenerator *) m_descriptor;
    if(m_currentDistanceFunctionIndex != value){
	m_currentDistanceFunctionIndex = value;
	m_currentDistanceFunction = m_distanceFunctions[m_currentDistanceFunctionIndex];
	descriptor->setDistanceFunction(m_currentDistanceFunction);
	m_descriptorParameter->setEnumValue("distanceFunction", m_currentDistanceFunctionIndex);
	emit descriptorChanged();
    }
}

void ShapeContextPresenter::syncronize(){
    ShapeContextGenerator *descriptor = (ShapeContextGenerator *) m_descriptor;
    m_descriptorParameter->setDoubleValue("minRho", descriptor->getMinRho());
    m_descriptorParameter->setDoubleValue("maxRho", descriptor->getMaxRho());
    m_descriptorParameter->setIntValue("binRho", descriptor->getBinRho());
    m_descriptorParameter->setIntValue("binPhi", descriptor->getBinPhi());
    if(m_distanceFunctions.size()){
	m_descriptorParameter->clearEnumParameter("distanceFunction");
	for(int i = 0; i < m_distanceFunctionNames.size(); i++){
	    m_descriptorParameter->insertEnumValue("distanceFunction", m_distanceFunctionNames[i]);
	}
	m_descriptorParameter->setEnumValue("peakFinder", m_currentDistanceFunctionIndex);
	descriptor->setDistanceFunction(m_currentDistanceFunction);
    }
}

void ShapeContextPresenter::reconnect(){
    connect(m_descriptorParameter, SIGNAL(parameterChanged(const QString&)), this, SLOT(changeParameter(const QString&)));
}
